package rsexplorer.rstree;

import rsexplorer.utils.ClassResolver;
import rsexplorer.utils.FieldFilter;

public abstract class FieldContainerTreeNode extends FieldFilterTreeNode {
    public static final int MAX_ARRAY_INDEX = 10;
    public static final int MAX_FIELD_LEVEL = 5;

    protected Object fieldObject;

    private int level;

    public FieldContainerTreeNode(Object userObject, Object fieldObject) {
        this(userObject, fieldObject, null, 0);
    }

    public FieldContainerTreeNode(Object userObject, Object fieldObject, FieldFilter filter) {
        this(userObject, fieldObject, filter, 0);
    }

    protected FieldContainerTreeNode(Object userObject, Object fieldObject, FieldFilter filter, int level) {
        super(userObject, filter);
        setSortChildren(false);
        this.fieldObject = fieldObject;
        this.level = level;
    }

    public void updateChildField(int index, Object userObject, Object fieldObject) {
        updateChildField((FieldContainerTreeNode)getChildAt(index), userObject, fieldObject);
    }

    public void updateChildField(FieldContainerTreeNode ftn, Object userObject, Object fieldObject) {
        Class<?> type = fieldObject.getClass();

        if (type == ftn.getFieldObject().getClass()) {
            ftn.update(userObject, fieldObject);
            //ftn.setFieldObject(fieldObject);
        } else {
            System.out.println("1: "+userObject + ":      "+fieldObject.getClass().getName());
            System.out.println("2: "+ftn.getUserObject() + ":      "+ftn.getFieldObject().getClass().getName());
            FieldContainerTreeNode newFtn = getFieldNode(userObject, fieldObject);

            remove(ftn);
            add(newFtn);//*/
        }
    }

    /**
     * Convenience method that creates a field node with filtration techniques.
     * @param userObject the name of the new node.
     * @param fieldObject the field object to be added.
     */
    public void addChildField(Object userObject, Object fieldObject) {
        if (level >= MAX_FIELD_LEVEL)
            return;

        FieldContainerTreeNode ftn = getFieldNode(userObject, fieldObject);

        if (ftn != null)
            add(ftn);
    }

    private FieldContainerTreeNode getFieldNode(Object userObject, Object fieldObject) {
        Class<?> type = fieldObject.getClass();

        if (type.isPrimitive() || ClassResolver.isSystemObject(fieldObject)) {
            if (shouldFilterPrimitive(fieldObject))
                return null;

            return new BasicFieldTreeNode(userObject, fieldObject);
        } else if (type.isArray()) {
            if (shouldFilterArray(fieldObject))
                return null;

            return new ArrayFieldTreeNode(userObject, fieldObject, filter, MAX_ARRAY_INDEX, level+1);
        } else {
            if (shouldFilterObject(fieldObject))
                return null;

            return new ObjectFieldTreeNode(userObject, fieldObject, filter, level+1);
        }
    }

    /**
     * Sets the field object.
     * @param fieldObject the new field object.
     */
    public void setFieldObject(Object fieldObject) {
        this.fieldObject = fieldObject;
    }

    /**
     * @return the current field object.
     */
    public Object getFieldObject() {
        return fieldObject;
    }

    /**
     * Updates this node.
     * @param userObject the new userObject.
     * @param fieldObject the new fieldObject.
     */
    abstract void update(Object userObject, Object fieldObject);
}
